# encoding: utf-8
"""
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    created by lane.chang on '17/10/2024'
    comment: 服务流程
"""
import json
from fastapi import APIRouter, Request, Body, Query

from config import Config
from project.core.exception import BizError
from project.core.function import json_response, async_run, Core
from project.lib.decorator import api_common, exec_duration
from project.model.basic import NotifyObject
from project.model.database.cariabot import Cariabot, CariabotColumn, CariabotColumnService, Organization, DeviceJpush
from project.micro_service.vision import Vision
from project.micro_service.zeus import Zeus
from project.middleware.jpush import JPush
from project.service.cariabot import CariabotService
from project.service.common.mqtt import MQTTService


home_router = APIRouter(prefix='/c', tags=['cariabot.homepage'])


@home_router.post('/login', summary='登录')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),))
@exec_duration(add_return=True)
async def do_login(request: Request,
                   # code: str = Body(..., title='账号'),
                   # password: str = Body(..., title='密码'),
                   # device=None
                   ):
    """
    **desc**: cariabot登录

    **url**: http(s)://{0}.udicaria.com/c/login

    **method**: POST

    **params**:

        <body>:
            code: 账号
            password: 密码

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    # # 并发执行nlu, nlg
    # result = await async_run(
    #     Core(func=Zeus.do_login(code=code, password=password), name='login_info'),
    #     Core(func=Zeus.get_device(device.dev_id), name='device')
    # )
    # ret_data = result.get('login_info', {})
    # organizations = ret_data.pop('organizations', [])
    # organization_map = {v['code']: v['name'] for v in organizations}
    # ret_data['device'] = {}
    # device = result.get('device')
    # if device:
    #     device.organization_name = organization_map.get(device.organization_code, '')
    #     ret_data['device'] = {
    #         'organization_code': device.organization_code,
    #         'organization_name': device.organization_name,
    #         'room_no': device.room_no,
    #         'dev_id': device.dev_id
    #     }

    # return json_response(data=ret_data)
    return json_response()


@home_router.get('/homepage', summary='首页')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), dev_info=True)
@exec_duration(add_return=True)
async def get_flow_list(request: Request, session=None, device=None):
    """
    **desc**: cariabot首页

    **url**: http(s)://{0}.udicaria.com/c/homepage

    **method**: GET

    **params**:

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data: {
                background_image: 背景图
                digital_human_id: 数字人id
                digital_human_image: 数字人图片
                awaken: 唤醒词
                voice_icon: 语音图标
                sidebar: [
                    {
                        id: 侧边栏id
                        name: 名称
                        icon_checked: 选中时的图标
                        icon_unchecked: 未选中时的图标
                        column_type: 栏目类型 flow(服务流程)/card(服务卡片)/evaluation(健康评估)/
                                    sleep(睡眠方案)/human(呼叫前台)/home(返回首页)/external(外部模块)
                                    /agent(智能助理)/shortcut(快捷入口)/voip(语音通话)/h5(h5页面)
                        tags: 栏目标签
                        preamble: 开场白
                        flow_code: 服务流程flow_code列表
                    }
                    ...
                ] 侧边栏项目
            }
            exec_time: 接口后端处理时长
        }
    """
    cariabot = await Cariabot.fetch_one(session, wheres=(Cariabot.organization_code == device.organization_code, ~Cariabot.is_deleted))
    if not cariabot:
        return json_response(data={})

    ret_data = cariabot.dict()

    # 侧边栏信息
    cariabot_columns = await CariabotColumn.fetch_all(session, wheres=(CariabotColumn.cariabot_id == cariabot.id, ~CariabotColumn.is_deleted), orders=CariabotColumn.rank)
    ret_data['sidebar'] = [v.dict() for v in cariabot_columns]

    # 快捷入口， 取出栏目id
    column_ids = [v.id for v in cariabot_columns if v.column_type == 'shortcut']
    column_services = await CariabotColumnService.fetch_all(session, wheres=(CariabotColumnService.column_id.in_(column_ids), ~CariabotColumnService.is_deleted))
    column_service_map = {v.column_id: v.code for v in column_services}

    for v in ret_data['sidebar']:
        v['flow_code'] = column_service_map.get(v['id'], '')

    return json_response(data=ret_data)


@home_router.get('/card/list', summary='服务卡片列表')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), dev_info=True)
@exec_duration(add_return=True)
async def get_card_list(request: Request,
                        sidebar_id: int = Query(..., title='侧边栏id'),
                        session=None, device=None):
    """
    **desc**: cariabot服务卡片列表

    **url**: http(s)://{0}.udicaria.com/c/card/list

    **method**: GET

    **params**:

        <query>:
            sidebar_id: 侧边栏id

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data: [] 原卡片列表
            exec_time: 接口后端处理时长
        }
    """
    # 侧边栏信息
    wheres = list()
    if sidebar_id:
        wheres.append(CariabotColumnService.column_id == sidebar_id)
    else:
        cariabot = await Cariabot.fetch_one(session, wheres=(Cariabot.organization_code == device.organization_code, ~Cariabot.is_deleted))
        if not cariabot:
            wheres.append(1 != 1)

        cariabot_columns = await CariabotColumn.fetch_all(session, wheres=(CariabotColumn.cariabot_id == cariabot.id, ~CariabotColumn.is_deleted, CariabotColumn.column_type == 'card'))
        column_ids = [v.id for v in cariabot_columns]
        wheres.append(CariabotColumnService.column_id.in_(column_ids))
    wheres.append(~CariabotColumnService.is_deleted)

    # 服务卡片信息
    services = await CariabotColumnService.fetch_all(session, wheres=wheres, orders=(CariabotColumnService.id,))
    card_codes = [v.code for v in services]
    cards = await Vision.get_cards_with_codes(organization_code=device.organization_code, codes=card_codes)

    return json_response(data=cards)


@home_router.get('/voip/list', summary='语音通话列表')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), dev_info=True)
@exec_duration(add_return=True)
async def get_voip_list(request: Request,
                        sidebar_id: int = Query(..., title='侧边栏id'),
                        name: str = Query('', title='联系人姓名，支持模糊查询'),
                        session=None, device=None):
    """
    **desc**: 语音通话列表

    **url**: http(s)://{0}.udicaria.com/c/voip/list

    **method**: GET

    **params**:

        <query>:
            sidebar_id: 侧边栏id
            name: 联系人姓名，支持模糊查询

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data: [
                {
                    code: 设备编号
                    name: 联系人姓名
                    rank: 排序
                }
            ]
            exec_time: 接口后端处理时长
        }
    """
    data = await CariabotService.get_cariabot_voip_list(session, device, sidebar_id=sidebar_id, name=name)
    return json_response(data=data)


@home_router.post('/device/register', summary='上报设备')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), dev_info=True)
@exec_duration(add_return=True)
async def do_device_jpush_register(request: Request,
                                   registration_id: str = Body(..., title='极光上报id', embed=True),
                                   session=None,
                                   device=None):
    """
    **desc**: 将设备上报极光平台

    **url**: http(s)://{0}.udicaria.com/c/device/register

    **method**: POST

    **params**:

        <body>:
            dev_id: 设备id
            registration_id: 极光上报id

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    await DeviceJpush.create_modify(session, wheres=(DeviceJpush.code == device.dev_id),
                                    code=device.dev_id,
                                    organization_code=device.organization_code,
                                    registration_id=registration_id)

    return json_response()


@home_router.get('/device/info', summary='设备信息')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), dev_info=True)
@exec_duration(add_return=True)
async def get_device_info(request: Request, session=None, device=None):
    """
    **desc**: 得到设备信息

    **url**: http(s)://{0}.udicaria.com/c/device/info

    **method**: GET

    **params**:

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data:
            exec_time: 接口后端处理时长
        }
    """
    organization = await Organization.fetch_one(session, wheres=(Organization.code == device.organization_code))
    if organization:
        device.organization = organization.dict()

    return json_response(data=device.dict())


@home_router.post('/device/notify', summary='通知设备')
@api_common(doc_replace=(('{0}', Config.ENV_DOC_FIX),), dev_info=True)
@exec_duration(add_return=True)
async def notify_device(request: Request,
                        content: str = Body(..., title='通知内容', description='语音播报内容', embed=True),
                        after_broadcast: str = Body('', title='播报完成后', description='only_broadcast(纯播报)/wakeup(打开麦克风)/call(打电话)'),
                        notify_object: NotifyObject = Body(None, title='通知对象'),
                        replay_count: int = Body(1, title='播放次数', description='播放次数 默认1'),
                        session=None, device=None):
    """
    **desc**: 通知设备

    **url**: http(s)://{0}.udicaria.com/c/device/notify

    **method**: POST

    **params**:

        <body>:
            content: 语音播报内容
            after_broadcast: 播报后  only_broadcast(完成)/wakeup(打开麦克风开启交互)/call(打电话)
            notify_object: 通知对象 姓名/手机号
            replay_count: 重复次数 默认: 1

    **return**:json数据结构::

        {
            code: 0(成功)/非0(失败)
            message: 成功返回success, 否则返回error信息
            data: {
                action: notify(通知)
                after_broadcast: 播报后  only_broadcast(纯播报)/wakeup(打开麦克风开启交互)/call(打电话)
                response: 数字人话术
                notify_object: {
                    name: 姓名
                    mobile: 联系号码
                }
            }
            exec_time: 接口后端处理时长
        }
    """
    content = {'action': 'notify', 'response': content, 'notify_object': notify_object.dict() if notify_object else {}, 'replay_count': replay_count}
    if not after_broadcast:
        if notify_object:
            after_broadcast = 'call'
        else:
            after_broadcast = 'only_broadcast'
    content['after_broadcast'] = after_broadcast

    device_jpush = await DeviceJpush.fetch_one(session, wheres=(DeviceJpush.code == device.dev_id))
    if not device_jpush:
        raise BizError('设备未上报')
    JPush.send(device_jpush.registration_id, content, title='预警')
    # MQTT 推送
    await MQTTService.push(topic=f'radar/{device.dev_id}', message=json.dumps(content, ensure_ascii=False).encode('utf-8'))

    return json_response(data=content)

